/// **************************************************************************************************
/// "Copyright (c) 2007 Sai Panyam, Inc.  All rights reserved."
/// **************************************************************************************************
/// Component Name   :	BlockModifier, Member of System72.NTextile 
/// Description      :	BlockModifier description
/// Author           :	Sai Panyam
/// Creation Date    :	November 09 2007
/// Modified Date    :              
/// Modified By      :
/// **************************************************************************************************
using System;
using System.Text.RegularExpressions;
using System.Web;
using System72.NTextile.RegexLibrary;

namespace System72.NTextile
{
    internal class BlockModifier : IModifier
    {
        #region Private Variables

        private readonly Operation m_operation;
        private readonly BlockModifierType m_blockModifierType;
        private AlignmentCollection m_supportedAlignments;
        private AttributeCollection m_supportedAttributes;
        private PunctuationCollection m_supportedPunctuations;
        private bool m_success;
        private readonly int m_parseOrder=1;
        private readonly ModifierType m_type;
        
        #endregion

        #region Constructor
        /// <summary>
        /// 
        /// </summary>
        /// <param name="blockModifierType"></param>
        public BlockModifier(BlockModifierType blockModifierType)
        {
            m_blockModifierType = blockModifierType;
            OperationFactory factory = new OperationFactory(m_blockModifierType);
            m_operation = factory.GetBlockOperation();
            m_type = m_operation.ModifierType;
        }

        #endregion
                
        #region Public Properties
        /// <summary>
        /// 
        /// </summary>
        public BlockModifierType BlockModifierType
        {
            get
            {
                return m_blockModifierType;
            }
        }
        /// <summary>
        /// 
        /// </summary>
        public string Tag
        {
            get
            {
                return (m_operation != null) ? m_operation.Tag : String.Empty;
            }
        }
        /// <summary>
        /// 
        /// </summary>
        public string Operator
        {
            get
            {
                return (m_operation != null) ? m_operation.Operator : String.Empty;
            }
        }
        /// <summary>
        /// 
        /// </summary>
        public Operation Operation
        {
            get
            {
                return m_operation;
            }
        }
        /// <summary>
        /// 
        /// </summary>
        public AlignmentCollection SupportedAlignments
        {
            get { return m_supportedAlignments; }
            set { m_supportedAlignments = value; }
        }
        /// <summary>
        /// 
        /// </summary>
        public AttributeCollection SupportedAttributes
        {
            get
            {
                return m_supportedAttributes;
            }
            set
            {
                m_supportedAttributes = value;
            }
        }
        /// <summary>
        /// 
        /// </summary>
        public PunctuationCollection SupportedPunctuations
        {
            get { return m_supportedPunctuations; }
            set { m_supportedPunctuations = value; }
        }
        /// <summary>
        /// 
        /// </summary>
        public bool Success
        {
            get { return m_success; }
            set { m_success = value; }
        }
        /// <summary>
        /// 
        /// </summary>
        public int ParseOrder
        {
            get { return m_parseOrder; }
        }
        /// <summary>
        /// 
        /// </summary>
        public ModifierType Type
        {
            get { return m_type; }
        }

        #endregion

        #region Public Methods
        /// <summary>
        /// 
        /// </summary>
        /// <param name="contentText"></param>
        /// <param name="excludedModifiers"></param>
        /// <returns></returns>
        public string GetXHTML(string contentText, ModifierCollection excludedModifiers)
        {
            if (m_operation!=null)
            {
                if (!excludedModifiers.ContainsModifier(this))
                {
                    string alignmentPattern = getAlignmentPattern();//Holds the pattern for ALL alignment (supported or not) for e.g. >,<,=,<>.
                    BlockRegex blockRegex = new BlockRegex(m_operation.RegExOperator, alignmentPattern);
                    MatchCollection matchCollection = blockRegex.GetMatches(contentText);
                    foreach (Match match in matchCollection)
                    {
                        //Since there is atleast one match then we can set Success to true
                        m_success = true;
                        string finalAttribute = String.Empty;
                        string matchText = match.Groups[6].Value.Trim();//Get the value of content text sans the operator
                        //We process alignments, attributes and punctuations for all except when notextile is encountered
                        if (m_blockModifierType!=BlockModifierType.NoTextile)
                        {
                            string alignOperator = match.Groups[2].Value;
                            Alignment alignment = (m_supportedAlignments != null) ? m_supportedAlignments.GetAlignmentByOperator(alignOperator) : null;
                            matchText = parseForAlignments(alignOperator, alignment, matchText, ref finalAttribute);
                            matchText = parseForAttributes(match, alignment, matchText, ref finalAttribute);
                            //If the modifier is a block code then Encode the match text
                            if (m_blockModifierType == BlockModifierType.Blockcode || m_blockModifierType == BlockModifierType.Preformat)
                            {
                                matchText = HttpUtility.HtmlEncode(matchText);
                            }
                            else//Parse for punctuations. Punctuation parsing is done only for non code blocks
                            {
                                matchText = parseForPunctuations(matchText);
                            }
                        }
                        matchText = Util.GetElementMarkUp(matchText, m_operation.Tag, finalAttribute);
                        //If the modifier is Blockcode then surround the mark up text within <pre></pre> tags with the
                        //same attributes as <code></code>
                        if (m_blockModifierType == BlockModifierType.Blockcode)
                        {
                            matchText = Util.GetElementMarkUp(matchText, "pre", finalAttribute);
                        }
                        contentText = matchText;
                    }
                }
            }
            return contentText;
        }
        
        #endregion

        #region Private Methods
        /// <summary>
        /// 
        /// </summary>
        /// <returns></returns>
        private string getAlignmentPattern()
        {
            string pattern = String.Empty;
            if (m_supportedAlignments != null && m_supportedAlignments.Count > 0)
            {
                pattern = "(";
                foreach (Alignment alignment in m_supportedAlignments)
                {
                    pattern += alignment.Operator + "|";//Append with the alternation regex operator
                }
                if (pattern.EndsWith("|"))
                {
                    pattern = pattern.Remove(pattern.Length - 1, 1);
                }
                pattern += ")?";
            }
            return pattern;
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="matchText"></param>
        /// <returns></returns>
        private string parseForPunctuations(string matchText)
        {
            if (m_supportedPunctuations != null && m_supportedPunctuations.Count > 0)
            {
                foreach (Punctuation punctuation in m_supportedPunctuations)
                {
                    matchText = punctuation.GetModifiedText(matchText);
                }
            }
            return matchText;
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="alignOperator"></param>
        /// <param name="alignment"></param>
        /// <param name="matchText"></param>
        /// <param name="finalAttribute"></param>
        /// <returns></returns>
        private string parseForAlignments(string alignOperator,Alignment alignment, string matchText, ref string finalAttribute)
        {
            if (alignment!=null)
            {
                Attribute styleAttribute = new Attribute(AttributeType.Style);
                styleAttribute.AttributeValue = alignment.AlignmentText;
                finalAttribute = styleAttribute.GetAttributeKeyValueText();
                //TODO: Replace only the operator, Not any instance of it in the text
                matchText = matchText.Replace(alignOperator, "");
            }
            return matchText;
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="match"></param>
        /// <param name="alignment"></param>
        /// <param name="matchText"></param>
        /// <param name="finalAttribute"></param>
        /// <returns></returns>
        private string parseForAttributes(Match match, Alignment alignment, string matchText, ref string finalAttribute)
        {
            if (m_supportedAttributes != null && m_supportedAttributes.Count > 0)
            {
                foreach (Attribute attribute in m_supportedAttributes)
                {
                    string matchValue;
                    string attributeValue = m_operation.GetAttributeText(match.Groups[3].Value, attribute, out matchValue);
                    if (attribute.AttributeType == AttributeType.Style)
                    {
                        if (matchValue != String.Empty)
                        {
                            if (alignment == null)
                            {
                                Attribute styleAttribute = new Attribute(AttributeType.Style);
                                styleAttribute.AttributeValue = attributeValue;
                                finalAttribute = styleAttribute.GetAttributeKeyValueText();
                            }
                            //TODO: Replace only the operator, Not any instance of it in the text
                            matchText = matchText.Replace(matchValue, "");
                        }
                        finalAttribute = String.Format(finalAttribute, attributeValue);
                    }
                    else
                    {
                        attribute.AttributeValue = attributeValue;
                        string attributeKeyValue = attribute.GetAttributeKeyValueText();
                        if (matchValue == String.Empty)
                        {
                            attributeKeyValue = String.Empty;
                        }
                        else
                        {
                            //TODO: Replace only the operator, Not any instance of it in the text
                            matchText = matchText.Replace(matchValue, "");
                        }
                        finalAttribute = finalAttribute + attributeKeyValue;
                    }

                }
            }
            return matchText;
        }

        #endregion

    }
}
